﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using xKnight.Analyzing;
using xKnight.Analyzing.BaseAnalyze;
using xKnight.Analyzing.Csrf;
using xKnight.Analyzing.EncodedXss;
using xKnight.Analyzing.SimpleXss;
using xKnight.Attacker.CSRF;
using xKnight.Attacking;
using xKnight.Attacking.EncodedXss;
using xKnight.Attacking.SimpleXss;
using xKnight.Models;
using xKnight.WebCrawling;
using xKnight.WebCrawling.Core.Authentication;
using xKnight.WebCrawling.Event;
using xKnight.WebCrawling.Models;

namespace xKnight
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        private Crawler _crawler;
        private delegate void UpdateUserInterface(CrawlAnnouncedEventArgs e);
        private delegate void UpdateUserInterfaceAttack(AttackAnnouncedEventArgs e);
        private delegate void UpdateUserInterfaceAnalyze(AnalyzeAnnouncedEventArgs e);

        private delegate void CompleteUserInterface(CrawlCompletedEventArgs e);
        private delegate void CompleteUserInterfaceAttack(AttackCompletedEventArgs e);
        private delegate void CompleteUserInterfaceAnalyze(AnalyzeCompletedEventArgs e);

        public MainWindow()
        {
            InitializeComponent();

            //if (!App.IsDbExist())
                //App.CreateDb();

            cmbAttackType.Items.Add("Simple Reflected Xss");
            cmbAttackType.Items.Add("Encoded Reflected Xss");
            cmbAttackType.Items.Add("CSRF");
        }

        private void btnStart_Click(object sender, RoutedEventArgs e)
        {
            int threadNumber = 0;
            bool valid = GetCrawlingThreadNumber(out threadNumber);

            if (!valid)
                return;

            string hostName = "";
            valid = GetHostName(out hostName);

            if (!valid)
                return;

            int maxDepth = 0;
            valid = GetMaxDepth(out maxDepth);

            if (!valid)
                return;

            InitCrawlModel(hostName, threadNumber, maxDepth);
            InitCrawlForm();
        }

        private void InitCrawlForm()
        {
            lsvCrawlStatus.Items.Clear();
            btnStart.IsEnabled = false;
            btnStop.IsEnabled = true;
        }

        private void InitCrawlModel(string hostName, int threadNumber, int maxDepth)
        {
            var crawlSetting = new WebCrawlingSetting();
            crawlSetting.CrawlSubDomains = true;
            Host host = new Host();

            host.HostName = hostName;
            crawlSetting.MaxDepth = maxDepth;

            AuthenticationSetting authenticationSetting = GetAuthenticationSetting();

            WebCrawlingTarget target = new WebCrawlingTarget(
                txtAddress.Text,
                authenticationSetting,
                int.Parse(txtCrawlThreads.Text));

            _crawler = new Crawler(crawlSetting, new WebCrawlingTarget[] { target });

            _crawler.CrawlCompleted += crawler_CrawlCompleted;
            _crawler.CrawlAnnounced += crawler_CrawlAnnounced;
            _crawler.CrawlStarted += crawler_CrawlStarted;

            _crawler.Crawl();
        }

        private AuthenticationSetting GetAuthenticationSetting()
        {
            if (chbEnableLogin.IsChecked==false)
                return null;

            return new AuthenticationSetting()
            {
                LoginPageUrl=txtLoginPage.Text,
                LoginFormAction=txtLoginFormAction.Text,
                LoginFormMethod="POST",
                PasswordField=txtPasswordField.Text,
                UsernameField=txtUsernameField.Text,
                PasswordValue=txtPassword.Text,
                UsernameValue=txtUsername.Text
            };
        }

        private bool GetHostName(out string hostName)
        {
            if (Uri.IsWellFormedUriString(txtAddress.Text, UriKind.Absolute))
            {
                hostName = txtAddress.Text;
                return true;
            }

            hostName = null;
            MessageBox.Show(".نام دامنه به درستی وارد نشده است", "خطا", MessageBoxButton.OK, MessageBoxImage.Error);
            return false;
        }

        private bool GetMaxDepth(out int maxDepth)
        {
            maxDepth = Int32.MaxValue;
            if (chbMaxDepth.IsChecked.Value)
            {
                bool valid = int.TryParse(txtMaxDepth.Text, out maxDepth);

                if (!valid || maxDepth <= 0)
                {
                    MessageBox.Show(".عمق پویش به درستی مشخص نشده است", "خطا", MessageBoxButton.OK, MessageBoxImage.Error);
                    return false;
                }
            }

            return true;
        }

        private bool GetCrawlingThreadNumber(out int threadNumber)
        {
            threadNumber = Int32.MaxValue;
            bool valid = int.TryParse(txtCrawlThreads.Text, out threadNumber);

            if (!valid || threadNumber <= 0)
            {
                MessageBox.Show(".تعداد پویشگران به درستی مشخص نشده است", "خطا", MessageBoxButton.OK, MessageBoxImage.Error);
                return false;
            }

            return true;
        }

        void crawler_CrawlStarted(object sender, CrawlStartedEventArgs e)
        {

        }

        void crawler_CrawlAnnounced(object sender, CrawlAnnouncedEventArgs e)
        {
            this.Dispatcher.BeginInvoke(new UpdateUserInterface(OnCrawlAnnounced), e);
        }

        private void OnCrawlAnnounced(CrawlAnnouncedEventArgs e)
        {
            lblTotalDownloadedLinks.Content = e.CrawlAnnounceItem.TotalPagesDownloaded;
            lblTotalForms.Content = e.CrawlAnnounceItem.TotalFormsFound;
            lblTotalUniqueForms.Content = e.CrawlAnnounceItem.TotalUniqueFormsFound;
            lblTotalUniqueLinks.Content = e.CrawlAnnounceItem.TotalUniqueLinksFound;
            lblTotalLinks.Content = e.CrawlAnnounceItem.TotalLinksFound;

            lsvCrawlStatus.Items.Add(e.CrawlAnnounceItem);
        }

        void crawler_CrawlCompleted(object sender, CrawlCompletedEventArgs e)
        {
            this.Dispatcher.BeginInvoke(new CompleteUserInterface(OnCrawlCompleted), e);
        }

        private void OnCrawlCompleted(CrawlCompletedEventArgs e)
        {
            btnStart.IsEnabled = true;
            btnStop.IsEnabled = false;
            MessageBox.Show(string.Format(".به شماره شناسه {0} انجام گرفت", e.CrawlSettingId), "پویش", MessageBoxButton.OK, MessageBoxImage.Information);
        }

        private void chbMaxDepth_Checked(object sender, RoutedEventArgs e)
        {
            txtMaxDepth.IsEnabled = true;
            txtMaxDepth.Text = "10";
        }

        private void btnStartAttack_Click(object sender, RoutedEventArgs e)
        {
            lsvAttack.Items.Clear();

            AttackType attackType = AttackType.EncodedXss;
            bool valid = GetAttackType(out attackType);

            if (!valid)
                return;

            int crawlId = 0;
            valid = GetAttackCrawlId(out crawlId);

            if (!valid)
                return;

            int threadNumber = 0;
            valid = GetAttackThreadNumber(out threadNumber);

            if (!valid)
                return;

            InitAttackModel(threadNumber, crawlId, attackType);
            initAttackForm();
        }

        private bool GetAttackThreadNumber(out int threadNumber)
        {
            threadNumber = Int32.MaxValue;
            bool valid = int.TryParse(txtAttackThreads.Text, out threadNumber);

            if (!valid || threadNumber <= 0)
            {
                MessageBox.Show(".تعداد پویشگران به درستی مشخص نشده است", "خطا", MessageBoxButton.OK, MessageBoxImage.Error);
                return false;
            }

            return true;
        }

        private bool GetAttackCrawlId(out int crawlId)
        {
            crawlId = Int32.MaxValue;
            bool valid = int.TryParse(txtCrawlId.Text, out crawlId);

            if (!valid || crawlId <= 0)
            {
                MessageBox.Show(".شماره پویش به درستی مشخص نشده است", "خطا", MessageBoxButton.OK, MessageBoxImage.Error);
                return false;
            }

            return true;
        }

        private bool GetAttackType(out AttackType attackType)
        {
            attackType = AttackType.SimpleXss;

            if (cmbAttackType.SelectedIndex == -1)
            {
                MessageBox.Show(".نوع حمله مشخص نشده است", "خطا", MessageBoxButton.OK, MessageBoxImage.Error);
                return false;
            }

            if (cmbAttackType.SelectedIndex == 0)
                attackType = AttackType.SimpleXss;
            else if (cmbAttackType.SelectedIndex == 1)
                attackType = AttackType.EncodedXss;
            else if (cmbAttackType.SelectedIndex == 2)
                attackType = AttackType.CSRF;

            return true;
        }

        private void initAttackForm()
        {
            lsvAttack.Items.Clear();
            btnStartAttack.IsEnabled = false;
        }

        private void InitAttackModel(int threadNumber, int crawlId, AttackType attackType)
        {
            AttackManager attackManager = null;
            attackManager = new AttackManager(crawlId, threadNumber, attackType);

            attackManager.AttackAnnounced += attackManager_AttackAnnounced;
            attackManager.AttackCompleted += attackManager_AttackCompleted;
            attackManager.AttackStarted += attackManager_AttackStarted;

            attackManager.Attack();
        }

        void attackManager_AttackStarted(object sender, AttackStartedEventArgs e)
        {
            //throw new NotImplementedException();
        }

        void attackManager_AttackCompleted(object sender, AttackCompletedEventArgs e)
        {
            this.Dispatcher.BeginInvoke(new CompleteUserInterfaceAttack(OnAttackCompleted), e);
        }

        private void OnAttackCompleted(AttackCompletedEventArgs e)
        {
            btnStartAttack.IsEnabled = true;
            MessageBox.Show(string.Format(".حمله به شماره شناسه {0} انجام گرفت", e.AttackId), "حمله", MessageBoxButton.OK, MessageBoxImage.Information);
        }

        void attackManager_AttackAnnounced(object sender, AttackAnnouncedEventArgs e)
        {
            this.Dispatcher.BeginInvoke(new UpdateUserInterfaceAttack(OnAtackAnnounced), e);
        }

        private void OnAtackAnnounced(AttackAnnouncedEventArgs e)
        {
            if (e.AnnounceItem is SimpleXssAttackAnnounceItem)
                lsvAttack.Items.Add((e.AnnounceItem as SimpleXssAttackAnnounceItem));
            else if (e.AnnounceItem is EncodedXssAttackAnnounceItem)
                lsvAttack.Items.Add((e.AnnounceItem as EncodedXssAttackAnnounceItem));
            else if (e.AnnounceItem is CsrfAttackAnnounceItem)
                lsvAttack.Items.Add((e.AnnounceItem as CsrfAttackAnnounceItem));
        }

        private void btnStartAnalyze_Click(object sender, RoutedEventArgs e)
        {
            lsvAnalysis.Items.Clear();

            int attackId = 0;
            bool valid = GetAttackId(out attackId);
            if (!valid)
                return;

            InitAnalyzeModel(attackId);
            InitAnalyzeForm();
        }

        private bool GetAttackId(out int attackId)
        {
            attackId = Int32.MaxValue;
            bool valid = int.TryParse(txtAttackId.Text, out attackId);

            if (!valid || attackId <= 0)
            {
                MessageBox.Show(".شماره پویش به درستی مشخص نشده است", "خطا", MessageBoxButton.OK, MessageBoxImage.Error);
                return false;
            }

            return true;
        }

        private void InitAnalyzeForm()
        {
            lsvAnalysis.Items.Clear();
            btnStartAnalyze.IsEnabled = false;
        }

        private void InitAnalyzeModel(int attackId)
        {
            AnalyzeManager analyzeManager = new AnalyzeManager(attackId);

            analyzeManager.AnalyzeAnnounced += analyzeManager_AnalyzeAnnounced;
            analyzeManager.AnalyzeCompleted += analyzeManager_AnalyzeCompleted;
            analyzeManager.AnalyzeStarted += analyzeManager_AnalyzeStarted;

            analyzeManager.Analyze();
        }

        void analyzeManager_AnalyzeStarted(object sender, Analyzing.BaseAnalyze.AnalyzeStartedEventArgs e)
        {
            //throw new NotImplementedException();
        }

        void analyzeManager_AnalyzeCompleted(object sender, Analyzing.BaseAnalyze.AnalyzeCompletedEventArgs e)
        {
            btnStartAnalyze.Dispatcher.BeginInvoke(new CompleteUserInterfaceAnalyze(OnAnalyzeCompleted), e);
        }

        private void OnAnalyzeCompleted(AnalyzeCompletedEventArgs e)
        {
            btnStartAnalyze.IsEnabled = true;
            MessageBox.Show(".آنالیز حمله انجام گرفت", "آنالیز", MessageBoxButton.OK, MessageBoxImage.Information);
        }

        void analyzeManager_AnalyzeAnnounced(object sender, AnalyzeAnnouncedEventArgs e)
        {
            this.Dispatcher.BeginInvoke(new UpdateUserInterfaceAnalyze(OnAnalyzeAnnounced), e);
        }

        private void OnAnalyzeAnnounced(AnalyzeAnnouncedEventArgs e)
        {
            if (e.AnnounceItem is SimpleXssAnalyzeAnnounceItem)
                lsvAnalysis.Items.Add((e.AnnounceItem as SimpleXssAnalyzeAnnounceItem));
            else if (e.AnnounceItem is EncodedXssAnalyzeAnnounceItem)
                lsvAnalysis.Items.Add((e.AnnounceItem as EncodedXssAnalyzeAnnounceItem));
            else if (e.AnnounceItem is CsrfAnalyzeAnnounceItem)
                lsvAnalysis.Items.Add((e.AnnounceItem as CsrfAnalyzeAnnounceItem));
        }

        private void chbMaxDepth_Unchecked(object sender, RoutedEventArgs e)
        {
            txtMaxDepth.IsEnabled = false;
            txtMaxDepth.Text = "نامحدود";
        }

        private void btnStop_Click(object sender, RoutedEventArgs e)
        {
            _crawler.Stop();
        }

    }
}
